﻿Namespace EIB.Bus.Addressing
    Public NotInheritable Class EIBPhysicalAddress
        Inherits EIBAddress

        Public Shared Invalid As New EIBPhysicalAddress("0.0.0")


        Sub New()
            _address = Invalid._address
        End Sub

        Sub New(address As UInt16)
            _address = address
        End Sub

        Sub New(zone As UInt16, line As UInt16, device As UInt16)
            ParseFromAddress3(zone, line, device)
        End Sub

        Sub New(data As Byte())
            If data.Length <> 2 Then Throw New ArgumentException("Argument value not valid. Data must be 2 byte long.", "data")

            ParseFromAddress3((data(0) And &HF0) >> 4, data(0) And &HF, data(1))
        End Sub

        Sub New(address As String)
            Dim s = address.Split(".")

            If s.Length = 3 Then
                Dim zone, line, device As UInt16
                If UInt16.TryParse(s(0), zone) AndAlso UInt16.TryParse(s(1), line) AndAlso UInt16.TryParse(s(2), device) Then
                    ParseFromAddress3(zone, line, device)
                Else
                    Throw New ArgumentException("Argument value not valid. Address parts must be numeric.", "address")
                End If
            Else
                Throw New ArgumentException("Agument value not valid. String must have format '#.#.#'.", "address")
            End If
        End Sub


        Private Sub ParseFromAddress3(zone As UInt16, line As UInt16, device As UInt16)
            If zone > &HF Then Throw New ArgumentException("Argument value not valid.", "zone")
            If line > &HF Then Throw New ArgumentException("Argument value not valid.", "line")
            If device > &HFF Then Throw New ArgumentException("Argument value not valid.", "device")

            _address = (zone << 12) + (line << 8) + device
        End Sub


        Public Overrides Function ToString() As String
            Return ToString("3")
        End Function

        Public Overloads Function ToString(format As String) As String
            Select Case format
                Case "3", "#.#.#"
                    Return String.Format("{0}.{1}.{2}", ((_address And &HF000) >> 12), ((_address And &HF00) >> 8), _address And &HFF)
                Case Else
                    Throw New ArgumentException("Argument value not valid.", "format")
            End Select
        End Function


        Private Function GetZone() As UInt16
            Return (_address And &HF000) >> 11
        End Function

        Private Function GetLine() As UInt16
            Return (_address And &HF00) >> 8
        End Function

        Private Function GetDevice() As UInt16
            Return _address And &HFF
        End Function


        Public Shared Operator +(a1 As EIBPhysicalAddress, a2 As EIBPhysicalAddress) As EIBPhysicalAddress
            Return New EIBPhysicalAddress(a1.GetZone + a2.GetZone, a1.GetLine + a2.GetLine, a1.GetDevice + a2.GetDevice)
        End Operator

        Public Shared Operator -(a1 As EIBPhysicalAddress, a2 As EIBPhysicalAddress) As EIBPhysicalAddress
            Return New EIBPhysicalAddress(a1.GetZone - a2.GetZone, a1.GetLine - a2.GetLine, a1.GetDevice - a2.GetDevice)
        End Operator


        Public Overloads Shared Function IsInvalid(address As EIBPhysicalAddress) As Boolean
            Return address._address = Invalid._address
        End Function

        Public Overrides Function IsInvalid() As Boolean
            Return _address = Invalid._address
        End Function

        Public Shared Function IsValidAddress(zone As UInt16, line As UInt16, device As UInt16) As Boolean
            Return Not zone > &HF AndAlso Not line > &HF AndAlso Not device > &HFF
        End Function
    End Class
End Namespace